透過 AVFoundation 來實作一個條碼掃描器。
QR Code(全稱為快速響應矩陣圖碼;英語:Quick Response Code),是二維條碼的一種,於1994年由日本 DENSO WAVE 公司發明。QR 來自英文 Quick Response 的縮寫,即快速反應,因為發明者希望 QR 碼可以讓其內容快速被解碼。(資料來源:維基百科 )
天瓏書局自助刷卡說明
現今 QR Code 已經普遍於用在各個地方,使用者可以透過簡單的相機掃描就能獲取 QR Code 內的資訊,而且不需要額外安裝任何的東西。這次的教學就教大家如何打造一個 QR Code 掃瞄器。
開始之前我們需要 import AVFoundation 來開發我們的 QR Code 掃瞄器,首先我們先宣告三個變數:
// 用來管理擷取活動和協調輸入及輸出數據流的對象。
var captureSession: AVCaptureSession?
// 核心動畫層,可以在擷取視頻時顯示視頻。
var videoPreviewLayer: AVCaptureVideoPreviewLayer?
// 稍後我們為了替我們的 QR Code 加上掃描框使用。
var qrCodeFrameView: UIView?
接著我們需要讓我們的實作 QRCode 掃瞄器的 ViewController 遵循 AVCaptureMetadataOutputObjectsDelegate 這個協議,稍後會用於獲取資料並解碼取得的 QR Code。這邊我們使用程式碼來解釋每一步的過程:
func configurationScanner() {
// 取得後置鏡頭來擷取影片
let deviceDiscoverySession = AVCaptureDevice.DiscoverySession(deviceTypes: [.builtInDualCamera], mediaType: AVMediaType.video, position: .back)
guard let captureDevice = deviceDiscoverySession.devices.first else {
print("無法獲取相機裝置")
return
}
do {
// 使用前一個裝置物件 captureDevice 來取得 AVCaptureDeviceInput 類別的實例
let input = try AVCaptureDeviceInput(device: captureDevice)
// 實例化 AVCaptureSession,設定 captureSession 的輸入裝置
captureSession = AVCaptureSession()
captureSession?.addInput(input)
// 實例化 AVCaptureMetadataOutput 物件並將其設定做為 captureSession 的輸出
let captureMetadataOutput = AVCaptureMetadataOutput()
captureSession?.addOutput(captureMetadataOutput)
// 設置 delegate 為 self,並使用預設的調度佇列來執行 Call back
// 當一個新的元資料被擷取時,便會將其轉交給委派物件做進一步處理
// 依照 Apple 的文件,我們這邊使用 DispatchQueue.main 來取得預設的主佇列
captureMetadataOutput.setMetadataObjectsDelegate(self, queue: DispatchQueue.main)
// 告訴 App 我們所想要處理 metadata 的對象對象類型
captureMetadataOutput.metadataObjectTypes = [AVMetadataObject.ObjectType.qr]
// 用於顯示我們的相機畫面
videoPreviewLayer = AVCaptureVideoPreviewLayer(session: captureSession!)
// 設置影片在 videoPreivewLayer 的顯示方式
videoPreviewLayer?.videoGravity = AVLayerVideoGravity.resizeAspectFill
videoPreviewLayer?.frame = view.layer.bounds
view.layer.addSublayer(videoPreviewLayer!)
// 設置 QR Code 掃描框
settingScannerFrame()
// 開始擷取畫面
captureSession!.startRunning()
} catch {
// 假如有錯誤發生、印出錯誤描述並且 return
print(error.localizedDescription)
return
}
}
設置 QR Code 掃描框:
func settingScannerFrame() {
qrCodeFrameView = UIView()
if let qrCodeFrameView = qrCodeFrameView {
qrCodeFrameView.layer.borderColor = UIColor.green.cgColor
qrCodeFrameView.layer.borderWidth = 2
view.addSubview(qrCodeFrameView)
// 將 qrCodeFrameView 排至畫面最前方
view.bringSubviewToFront(qrCodeFrameView)
}
}
如此一來我們建置 QR Code 掃瞄器的部分就到這邊結束,這時我們還需要做一件事情,iOS 需要在 App 開發者在取用相機之前,必須取得使用者的允許。所以我們會在 Info.plist 中加入 key 為Privacy - Camera Usage Description ,而後面的值我們可以稍微描述一下為什麼需要取用相機:
我們先前有遵循過 AVCaptureMetadataOutput ,當我們掃描到了我們想要識別的條碼後,會調用這個 AVCaptureMetadataOutputDelegate方法,我們需要實作此 Delegate 方法,來執行 metaData 的轉換程序:
func metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) {
// 如果 metadataObjects 是空陣列
// 那麼將我們搜尋框的 frame 設為 zero,並且 return
if metadataObjects.isEmpty {
qrCodeFrameView?.frame = CGRect.zero
return
}
// 如果能夠取得 metadataObjects 並且能夠轉換成 AVMetadataMachineReadableCodeObject(條碼訊息)
if let metadataObj = metadataObjects[0] as? AVMetadataMachineReadableCodeObject {
// 判斷 metadataObj 的類型是否為 QR Code
if metadataObj.type == AVMetadataObject.ObjectType.qr {
// 如果 metadata 與 QR code metadata 相同,則更新搜尋框的 frame
let barCodeObject = videoPreviewLayer?.transformedMetadataObject(for: metadataObj)
qrCodeFrameView?.frame = barCodeObject!.bounds
if let value = metadataObj.stringValue {
print(value)
}
}
}
}
接著讓我們來測試能不能夠印出 QR Code 上的資訊吧!可以自己新增一個 QR Code 來測試功能是否正確,這邊我提供一個 QR Code 給大家測試:
鐵人賽加油!!!
這邊我為了測試結果,所以我在掃描到 QR Code 的時候跳出一個 AlertController,並且顯示我們所獲取的資訊:
那麼這次的教學就到這邊結束了,目前我們能夠獲取 QR Code 上面的資訊,下次教學我們會額外對這個 QRCode 的掃瞄器進行額外的設定,結合出一些新的功能,希望經由這次教學大家能夠學會開發一個能夠掃條碼的應用程式。